package com.hdw.med.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hdw.common.util.DBUtil;
import com.hdw.common.util.SnowflakeIdWorker;
import com.hdw.common.util.SpringContextUtil;
import com.hdw.common.vo.PaginationVO;
import com.hdw.med.api.BaseDbService;
import com.hdw.med.bean.model.BaseDb;
import com.hdw.med.conf.BaseDBComponent;
import com.hdw.med.mapper.BaseDbMapper;
import com.hdw.med.mapper.TestDynamicDataSourceMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * baseDb服务实现类
 * Created by hozeData on 2021/05/21.
 */
@Service
@Transactional
public class BaseDbServiceImpl implements BaseDbService {

    private static final Logger LOGGER = LoggerFactory.getLogger(BaseDbServiceImpl.class);

    @Value("${oracle.datasource.driver-class-name}")
    private String oracleDriver;
    @Value("${sqlserver.datasource.driver-class-name}")
    private String sqlserverDriver;
    @Value("${mysql.datasource.driver-class-name}")
    private String mysqlDriver;

    @Autowired
    private TestDynamicDataSourceMapper testDynamicDataSourceMapper;
    @Autowired
    private BaseDbMapper baseDbMapper;

    @Override
    public int insert(BaseDb baseDb) {
        baseDb.setDriver(getDBDriverClass(baseDb.getEuTp()));
        if (baseDb.getIdDb() == null) {
            Long uuid32 = SnowflakeIdWorker.getId();
            baseDb.setIdDb(uuid32);
        }
        this.addDataSource(baseDb);
        return baseDbMapper.insert(baseDb);
    }

    @Override
    public int insertSelective(BaseDb baseDb) {
        baseDb.setDriver(getDBDriverClass(baseDb.getEuTp()));

        if (baseDb.getIdDb() == null) {
            Long uuid32 = SnowflakeIdWorker.getId();
            baseDb.setIdDb(uuid32);
        }

        this.addDataSource(baseDb);
        return baseDbMapper.insertSelective(baseDb);
    }

    @Override
    public int deleteById(Long idDb) {
        this.removeDataSource(idDb.toString());
        return baseDbMapper.deleteByPrimaryKey(idDb);
    }

    @Override
    public String testDB(BaseDb baseDb) {
        baseDb.setDriver(getDBDriverClass(baseDb.getEuTp()));
        baseDb.setIdDb(-1L);
        String msg = null;
        Connection conn = null;
        ResultSet rs = null;
        DataSource datasource = null;
        try {
            datasource = BaseDBComponent.createDataSource(baseDb);
            conn = datasource.getConnection();
            rs = DBUtil.query(conn, getTestSQL(baseDb.getEuTp()), 1000, 10000000);
            ResultSetMetaData metaData = rs.getMetaData();
            rs.next();
            byte[] bytes = rs.getBytes(1);
            String s1 = new String(bytes, baseDb.getCharacterSet());
            msg = "成功！ 正确显示这句话，则字符集正确：" + s1;
        } catch (Exception e) {
            msg = "失败！具体错误信息为：" + e.getLocalizedMessage();
        } finally {
            DBUtil.closeDBResources(rs, null, conn);
            DBUtil.closeDataSource(datasource);
        }
        return msg;
    }

    @Override
    public List<Map<String, Object>> testDynamicDataSource() {
        return testDynamicDataSourceMapper.testDynamicDataSource();
    }

    @Override
    public int updateByIdSelective(BaseDb baseDb) {
        baseDb.setDriver(getDBDriverClass(baseDb.getEuTp()));
        this.addDataSource(baseDb);
        return baseDbMapper.updateByPrimaryKeySelective(baseDb);
    }

    @Override
    public int updateById(BaseDb baseDb) {
        baseDb.setDriver(getDBDriverClass(baseDb.getEuTp()));
        this.addDataSource(baseDb);
        return baseDbMapper.updateByPrimaryKey(baseDb);
    }

    @Override
    public BaseDb getById(Long idDb) {
        return baseDbMapper.selectByPrimaryKey(idDb);
    }

    @Override
    public List<BaseDb> findByModel(BaseDb baseDb) {

        Set<Object> dbName = DBUtil.getDbName();
        List<BaseDb> byModel = baseDbMapper.findByModel(baseDb);

        byModel.sort((a, b) -> b.getEuDbTp().compareTo(a.getEuDbTp()));

        for (BaseDb db : byModel) {
            boolean contains = dbName.contains(db.getIdDb().toString());
            db.setStatus(contains ? "可用" : "不可用");
        }
        return byModel;
    }

    @Override
    public PaginationVO<BaseDb> findPageByModel(BaseDb baseDb, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum == null ? 1 : pageNum, pageSize == null ? 10 : pageSize);
        List<BaseDb> quesList = baseDbMapper.findByModel(baseDb);
        PageInfo<BaseDb> pageInfo = new PageInfo<>(quesList);
        PaginationVO<BaseDb> paginationVo = new PaginationVO(pageInfo.getTotal(), pageInfo.getList());
        return paginationVo;
    }

    public String getTestSQL(String euTp) {
        if (DBUtil.DB_TYPE_MYSQL.equals(euTp)) return "select '字符集编码正确' val";
        else if (DBUtil.DB_TYPE_ORACLE.equals(euTp)) return "select '字符集编码正确' val from dual";
        else if (DBUtil.DB_TYPE_SQLSERVER.equals(euTp)) return "select '字符集编码正确' val";
        else return null;
    }


    public String getDBDriverClass(String euTp) {
        if (DBUtil.DB_TYPE_MYSQL.equals(euTp)) return mysqlDriver;
        else if (DBUtil.DB_TYPE_ORACLE.equals(euTp)) return oracleDriver;
        else if (DBUtil.DB_TYPE_SQLSERVER.equals(euTp)) return sqlserverDriver;
        else return null;
    }

    public void addDataSource(BaseDb baseDb) {
        if ("0".equals(baseDb.getFgStop())) {
            BaseDBComponent bean = SpringContextUtil.getBean(BaseDBComponent.class);
            bean.addDataSource(baseDb);
        } else {
            removeDataSource(baseDb.getIdDb().toString());
        }
    }

    public void removeDataSource(String key) {
        BaseDBComponent bean = SpringContextUtil.getBean(BaseDBComponent.class);
        bean.removeDataSource(key);
    }
}
